#include "stdafx.h"
#include "FutureStep.h"

#include "ChessStatus.h"

using namespace ExperientialSystem;

FutureStep::FutureStep(WinnerChecker* winnerChecker):_winnerChecker(winnerChecker)
{

}

FutureStep::~FutureStep()
{
}

void FutureStep::Update(IStatus* status)
{
	ChessStatus* chessStatus = dynamic_cast<ChessStatus*>(status);
	vector<ChessStatus*> statusChain;
	statusChain.push_back(chessStatus);
	InternalUpdate(statusChain, 0);
}

void FutureStep::InternalUpdate(vector<ChessStatus*>& statusChain, int Depth)
{
	if (Depth >= UPDATE_DEPTH) return;
	
	ChessStatus* curChessStatus = statusChain.back();
	ChessStatus::Color toGo = curChessStatus->ToGo();

	//Search for my next step.
	auto nextStatus = curChessStatus->GetAllNextStatus();
	vector<vector<ChessStatus*>> nextStatusChains;
	for (auto next : nextStatus)
	{
		ChessStatus* nextChessStatus = dynamic_cast<ChessStatus*>(next);
		if (BlackWin(toGo,nextChessStatus) || WhiteWin(toGo, nextChessStatus))
		{
			//Update value for black win.
			curChessStatus->SetWinRate(nextChessStatus, WIN_VALUE);
			UpdateStatusChain(statusChain, WIN_VALUE);
		}
		else
		{
			//For next search
			vector<ChessStatus*> nextChain;
			nextChain.push_back(nextChessStatus);
			nextStatusChains.push_back(nextChain);
		}
	}

	//Search for next opposite step.
	for (auto nextChain : nextStatusChains)
	{
		auto nextStatus = nextChain.back();
		auto allOpStatus = nextStatus->GetAllNextStatus();
		for (auto opStatus : allOpStatus)
		{
			ChessStatus* opNextChessStatus = dynamic_cast<ChessStatus*>(opStatus);
			if (BlackWin(nextStatus->ToGo(), opNextChessStatus) || WhiteWin(nextStatus->ToGo(), opNextChessStatus))
			{
				//I am losing and update value.
				curChessStatus->SetWinRate(nextStatus, LOSE_VALUE);
				//Update win rate.
				nextStatus->SetWinRate(opNextChessStatus, WIN_VALUE);

				UpdateStatusChain(nextChain, WIN_VALUE);
			}
			else
			{
				//Get opposite win rate.
				double winrate;
				my_assert(nextStatus->GetWinRate(opNextChessStatus, winrate));
// 				//Update my win rate.
// 				double myWinrate = 1 - winrate;
// 				curChessStatus->UpdateWinRate(nextStatus, myWinrate);

				UpdateStatusChain(nextChain, winrate);

				vector<ChessStatus*> nextNextChain = nextChain;
				nextNextChain.push_back(opNextChessStatus);
				InternalUpdate(nextNextChain, Depth + 1);
			}
		}
	}
}

bool FutureStep::BlackWin(const ChessStatus::Color togo, ChessStatus * status) const
{
	return togo==ChessStatus::Black && _winnerChecker->Check(status) == WinnerChecker::Black;
}

bool FutureStep::WhiteWin(const ChessStatus::Color togo, ChessStatus * status) const
{
	return togo == ChessStatus::White && _winnerChecker->Check(status) == WinnerChecker::White;
}

void FutureStep::UpdateStatusChain(vector<ChessStatus*>& statusChain, double winRate)
{
	if (statusChain.size() < 2) return;

	double curWinRate = 1 - winRate;
	for (vector<ChessStatus*>::const_reverse_iterator iter=statusChain.rbegin()+1;
		iter != statusChain.rend(); ++iter)
	{
		auto curStatus = *iter;
		auto nextStatus = *(iter - 1);

		curStatus->UpdateWinRate(nextStatus, curWinRate);
		//Win rate of The previous status is opposite.
		curWinRate = 1 - curWinRate;
	}
}
